using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Barebones.Components;
using Barebones.Dependencies;
using Microsoft.Xna.Framework.Graphics;
using Meat.Rendering;
using Barebones.Framework;
using Meat.Animation;

namespace Meat.Resources.Factory
{
    public class EZBake : EngineComponent
    {
        ResourceLoader m_Loader;
        SamplerState m_ParralaxState = new SamplerState()
        {
            AddressU = TextureAddressMode.Wrap,
            AddressV = TextureAddressMode.Clamp
        };

        public override IEnumerable<Barebones.Dependencies.IDependency> GetDependencies()
        {
            yield return new Dependency<ResourceLoader>(item => m_Loader = item, item => m_Loader = null);
        }

        public void MakeSprite(Entity toturn, Vector2 size, String texture_name)
        {
            MakeSprite(toturn, size, texture_name, 1, 0);
        }

        public void MakeSprite(Entity toturn, Vector2 size, String texture_name, int frame_count, int fps)
        {
            //TODO reuse billboards and use transforms (once entities can be stacked)
            AbstractHandle billboard = CreateBillboard(0.5f * size, "Billboard_" + Guid.NewGuid().ToString(), frame_count);

            IResource texres;
            if (!m_Loader.TryGetResource(texture_name, out texres))
            {
                texres = new ContentResource<Texture2D>(texture_name);
                m_Loader.AddResource(texres);
            }

            toturn.AddComponent(billboard);
            toturn.AddComponent(texres.ToHandle());
            toturn.AddComponent(new RenderSettings());

            if (frame_count > 1)
                toturn.AddComponent(new TextureAnimator(frame_count, fps));
        }

        public void MakeParallaxSprite(Entity toturn, Vector2 size, String texture_name, float mouvement_modifier)
        {
            //TODO reuse billboards and use transforms (once entities can be stacked)
            AbstractHandle billboard = CreateUserBillboard(0.5f * size, "Billboard_" + Guid.NewGuid().ToString(), 1);

            IResource texres;
            if (!m_Loader.TryGetResource(texture_name, out texres))
            {
                texres = new ContentResource<Texture2D>(texture_name);
                m_Loader.AddResource(texres);
            }

            toturn.AddComponent(billboard);
            toturn.AddComponent(texres.ToHandle());
            toturn.AddComponent(new RenderSettings()
                {
                    Sampler = m_ParralaxState
                });
            toturn.AddComponent(new UserVertexModifier(size)
                {
                    MouvementModifier = mouvement_modifier
                });
        }

        public AbstractHandle CreateBillboard(Vector2 half_size, String name, int framecount)
        {
            if (m_Loader == null)
                throw new InvalidOperationException("Can't create anything without having access to the resource loader");

            List<VertexPositionNormalTexture> billboard = CreateBillboardVertexList(half_size, Vector2.Zero, new Vector2(1, 1), framecount);

            IResource billboardResource = new CustomResource<VertexBufferResource<VertexPositionNormalTexture>>(name,
                                    new VertexBufferResource<VertexPositionNormalTexture>(billboard, 2, PrimitiveType.TriangleList));

            m_Loader.AddResource(billboardResource);

            return billboardResource.ToHandle();
        }

        public AbstractHandle CreateUserBillboard(Vector2 half_size, String name, int framecount)
        {
            if (m_Loader == null)
                throw new InvalidOperationException("Can't create anything without having access to the resource loader");

            List<VertexPositionNormalTexture> billboard = CreateBillboardVertexList(half_size, Vector2.Zero, new Vector2(1, 1), framecount);

            IResource billboardResource = new CustomResource<UserVertexResource<VertexPositionNormalTexture>>(name,
                                    new UserVertexResource<VertexPositionNormalTexture>(billboard, 2, PrimitiveType.TriangleList));

            m_Loader.AddResource(billboardResource);

            return billboardResource.ToHandle();
        }

        List<VertexPositionNormalTexture> CreateBillboardVertexList(Vector2 half_size, Vector2 min_tex, Vector2 max_tex, int frame_count)
        {
            List<VertexPositionNormalTexture> vertices = new List<VertexPositionNormalTexture>();

            float increment = 1.0f / frame_count;

            for (int i = 0; i < frame_count; ++i)
            {
                float xmin = i * increment;
                float xmax = (i + 1) * increment;
                float ymin = 1;
                float ymax = 0;

                vertices.AddRange(new VertexPositionNormalTexture[]{
                    new VertexPositionNormalTexture( new Vector3(-half_size, 0), Vector3.UnitZ, new Vector2(xmin,ymin) ),
                    new VertexPositionNormalTexture( new Vector3(half_size, 0), Vector3.UnitZ, new Vector2(xmax,ymax) ),
                    new VertexPositionNormalTexture( new Vector3(-half_size.X, half_size.Y, 0), Vector3.UnitZ, new Vector2(xmin,ymax) ),
                
                    new VertexPositionNormalTexture( new Vector3(-half_size, 0), Vector3.UnitZ, new Vector2(xmin,ymin) ),
                    new VertexPositionNormalTexture( new Vector3(half_size.X, -half_size.Y, 0), Vector3.UnitZ, new Vector2(xmax,ymin) ),
                    new VertexPositionNormalTexture( new Vector3(half_size, 0), Vector3.UnitZ, new Vector2(xmax,ymax) ),
                });
            }

            return vertices;
        }
    }
}
